#include "command.h"
int compar(const struct dirent **a, const struct dirent **b) {
    return strcmp((*a)->d_name, (*b)->d_name);
}
int filter(const struct dirent *entry) {
    if (entry->d_name[0] == '.') return 0; // 过滤隐藏文件
    return 1;
}
/* Usage:  */// 全局变量，用于统计总目录数和文件数
static int dirs = 0;
static int files = 0;

// 深度优先搜索打印目录树
// dirpath: 要递归遍历的根目录
// width: 打印宽度，用于控制缩进，增强视觉层次感
void DFS_print(char* dirpath, int width) {
    DIR* dirp = opendir(dirpath);
    ERROR_CHECK(dirp, NULL, "opendir"); // 检查目录是否成功打开

    struct dirent* pdirent;
    while ((pdirent = readdir(dirp)) != NULL) { // 循环读取目录项
                                                // 跳过 "." 和 ".." 这两个特殊目录
        if (strcmp(pdirent->d_name, ".") == 0 ||
            strcmp(pdirent->d_name, "..") == 0) {
            continue;
        }
        // 打印前缀和缩进，构建树形结构的视觉效果
        printf("└");
        for (int i = 1; i < width; ++i) {
            printf("─");
        }
        // 打印当前文件或目录的名称（先序遍历）
        printf("%s\n", pdirent->d_name);
        // 如果是目录，则递归调用自己，继续深入遍历
        if (pdirent->d_type == DT_DIR) {        // DT_DIR 表示目录文件
            dirs++;
            char path[1024] = { 0 };
            sprintf(path, "%s%s%s", dirpath, "/", pdirent->d_name); // 构建递归调用的目录路径名
            DFS_print(path, width + 4); // 递归调用，增加宽度以增加缩进
        }
        else {
            // 文件数++
            files++;
        }
    }
    // 完成目录遍历后关闭目录
    closedir(dirp);
}

int commandExcute(usrInfo_t *usrInfo,train_t *train,threadPool_t *pThreadPool){

    char *dirStart="/home/sun/wd/ex";
    char cwd[4096];
    char *buf=NULL;
    char *savePtr=NULL;
    buf=train->argv;
    Stack_t tmpStack;
    initStack(&tmpStack);
    /* copyStack(&usrInfo->virtulDirectory,&tmpStack); */
    if(buf[0]=='/'||buf[0]=='~'){
        /* while(!isStackEmpty(&tmpStack)){ */
            /* popStack(&tmpStack); */
        /* } */ 
    }
    else{
        // 相对路径
        copyStack(&usrInfo->virtulDirectory,&tmpStack);
    }
    commandType ret;
    char cachePath[128]={0};
    char *pathSege=NULL;
    pathSege=strtok_r(buf,"/",&savePtr);
    while (pathSege) {
        if (strcmp("..", pathSege) == 0) {
            popStack(&tmpStack);
        }
        else if(strcmp(".",pathSege)==0){

        }
        else{
            pushStack(&tmpStack, pathSege);
        }
        pathSege = strtok_r(NULL, "/", &savePtr);
    }
    if(train->command != MKDIR && train->command != PUTS){
        // 不是创建文件夹和上传的命令，检查完整路径是否正确
        sPrintfStack(&tmpStack,cachePath);
        snprintf(cwd, sizeof(cwd), "%s%s", dirStart, cachePath);
        if(access(cwd,F_OK)!=0){
            ret=ERROR;
            send(usrInfo->netFd,&ret,sizeof(int),0);
            return 0;
        }
        strcpy(usrInfo->truthPath,cwd);
    }
    else{
        // mkdir 和命令检查上一级目录是否正确
        char *dirName=popStack(&tmpStack);
        sPrintfStack(&tmpStack,cachePath);
        snprintf(cwd, sizeof(cwd), "%s%s", dirStart, cachePath);
        pushStack(&tmpStack,dirName);
        if(access(cwd,F_OK)!=0){
            ret=ERROR;
            send(usrInfo->netFd,&ret,sizeof(int),0);
            return 0;
        }
        sPrintfStack(&tmpStack,cachePath);
        snprintf(cwd, sizeof(cwd), "%s%s", dirStart, cachePath);
        strcpy(usrInfo->truthPath,cwd);
    }
    if(train->command==CD){
        // 进入指定目录
        // 相对路径 第一个字符是字母 
        // 绝对路径 第一个字符是/
        // .当前目录 ..上一级目录
        usrInfo->virtulDirectory=tmpStack;
        strcpy(usrInfo->cachePath,cachePath);
        usrInfo->flag=true;
        snprintf(cwd, sizeof(cwd), "%s%s", dirStart, usrInfo->cachePath);
        strcpy(usrInfo->truthPath,cwd);
        ret=CD;
        send(usrInfo->netFd,&ret,sizeof(ret),0);
    }
    else if(train->command==PWD){
        //显示当前路径
        printf("%s\n",usrInfo->cachePath);
        int len=strlen(usrInfo->cachePath);
        ret=PWD;
        send(usrInfo->netFd,&ret,sizeof(int),0);
        if(len==0){
            len=-1;
            send(usrInfo->netFd,&len,sizeof(int),0);
        }
        else{
            send(usrInfo->netFd,&len,sizeof(int),0);
            send(usrInfo->netFd,usrInfo->cachePath,len,0);
        }
    }
    else if(train->command==LS){
        struct dirent **namelist;
        int n = scandir(cwd, &namelist, filter, compar);
        if (n < 0) {
            perror("scandir");
            return 1;
        }
        ret=LS;
        send(usrInfo->netFd,&ret,sizeof(int),0); 
        send(usrInfo->netFd,&n,sizeof(int),0); 
        printf("目录中共有 %d 个文件（非隐藏）:\n", n);
        for (int i = 0; i < n; i++) {
            printf("%s  ", namelist[i]->d_name);
            int len=strlen(namelist[i]->d_name);
            send(usrInfo->netFd,&len,sizeof(int),0); 
            send(usrInfo->netFd,namelist[i]->d_name,len,0); 
            free(namelist[i]); // 释放单个目录项内存
        }
        printf("\n");
        free(namelist); // 释放目录项数组内存

    }
    else if(train->command==PUTS){
        printf("客户端上传文件\n");
        ret=PUTS;
        send(usrInfo->netFd,&ret,sizeof(int),0);
        recvFileFromClient(usrInfo);
    }
    else if(train->command==GETS){
        printf("客户端下载文件\n");
        ret=GETS;
        send(usrInfo->netFd,&ret,sizeof(int),0);
        sendFileToClient(usrInfo);
    }
    else if(train->command==REMOVE){
        unlink(cwd);
        ret=REMOVE;
        /* send(usrInfo->netFd,&ret,sizeof(int),0); */
    }
    else if(train->command==RMDIR){
        rmdir(cwd);
        ret=RMDIR;
        /* send(usrInfo->netFd,&ret,sizeof(int),0); */
    }
    else if(train->command==MKDIR){
        if (mkdir(cwd, 0755) == -1) {
            perror("创建目录失败");
            return 1;
        }
        ret=MKDIR;
        /* send(usrInfo->netFd,&ret,sizeof(int),0); */
        printf("目录创建成功\n");
    }
    else if(train->command==TREE){
        // 打印根目录名称
        printf("%s\n", cachePath);

        // 从根目录开始深度优先遍历打印目录树, 初始-打印4个
        DFS_print(cwd, 4);
        printf("\n%d directories, %d files\n", dirs, files);
        dirs=0;
        files=0;
    }
    return 0;
}
